﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace FrontDisplay.Controls
{
    /// <summary>
    /// Interaction logic for ScrollControl.xaml
    /// </summary>
    public partial class ScrollControl : UserControl
    {
        private readonly DispatcherTimer _animationTimer;
        private int _currentItem;
        private double _offset;
        private bool _isMoveLeft;
        private DispatcherTimer _autoscrollTimer;
        private int _autoScrollInterval = 3;
        private LinearGradientBrush _opacityGradientBrush;

        private int CurrentItem
        {
            get
            {
                return _currentItem;
            }
            set
            {
                _currentItem = value;
                if (_currentItem <= 0)
                {
                    _currentItem = 0;
                }
                if (_currentItem >= ContentPanel.Children.Count - ControlsPerPage)
                {
                    _currentItem = ContentPanel.Children.Count - ControlsPerPage;
                }
                UpdateNavigationButtons();
            }
        }

        private double ControlWidth { get; set; }

        private int _controlPerPage;

        public int ControlsPerPage
        {
            get { return _controlPerPage; }
            set
            {
                _controlPerPage = value;
                if (_controlPerPage <= 0)
                {
                    _controlPerPage = 1;
                }
                //TODO: change from fixed size
                ControlWidth = 800.0 /_controlPerPage;
            }
        }

        public bool IsAutoScroll { get; set; }

        public bool IsCircularScroll { get; set; }

        /// <summary>
        /// Auto scroll interval in seconds.
        /// </summary>
        public int AutoScrollInterval
        {
            get { return _autoScrollInterval; }
            set { _autoScrollInterval = value; }
        }

        public ScrollControl()
        {
            ControlsPerPage = 2;

            InitializeComponent();

            _opacityGradientBrush = new LinearGradientBrush
                {
                    StartPoint = new Point(0, 0),
                    EndPoint = new Point(1, 0),
                    GradientStops = new GradientStopCollection
                        {
                            new GradientStop(Colors.Transparent, 0.01),
                            new GradientStop(Colors.Black, 0.09),
                            new GradientStop(Colors.Black, 1 - 0.09),
                            new GradientStop(Colors.Transparent, 1 - 0.01)
                        }
                };

            _animationTimer = new DispatcherTimer();
            _animationTimer.Tick += ScrollTimerTick;
            _animationTimer.Interval = new TimeSpan(Animation.TimerInterval * TimeSpan.TicksPerMillisecond);

            Loaded += ControlLoaded;
            Unloaded += ControlUnloaded;

            UpdateNavigationButtons();
        }

        private void ControlLoaded(object sender, RoutedEventArgs e)
        {
            if (_autoscrollTimer == null)
            {
                _autoscrollTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(AutoScrollInterval) };
                _autoscrollTimer.Tick += AutoScrollTimerTick;
            }
            if (IsAutoScroll)
            {
                _autoscrollTimer.Start();
            }
        }

        private void AutoScrollTimerTick(object sender, EventArgs e)
        {
            if ((IsCircularScroll) || (CurrentItem < ContentPanel.Children.Count - ControlsPerPage))
            {
                ScrollToNextItem();
            }
            else
            {
                //TODO: make smooth animation.
                ScrollToLeftEnd();
            }
        }

        private void ControlUnloaded(object sender, RoutedEventArgs e)
        {
            if (_autoscrollTimer != null)
            {
                _autoscrollTimer.Stop();
            }
        }

        private void UpdateNavigationButtons()
        {
            if (ContentPanel.Children.Count <= ControlsPerPage)
            {
                LeftButton.Visibility = Visibility.Hidden;
                RightButton.Visibility = Visibility.Hidden;
                return;
            }
            if (IsCircularScroll)
            {
                LeftButton.Visibility = Visibility.Visible;
                RightButton.Visibility = Visibility.Visible;
                return;
            }
            LeftButton.Visibility = CurrentItem == 0 ? Visibility.Hidden : Visibility.Visible;
            RightButton.Visibility = CurrentItem == (ContentPanel.Children.Count - ControlsPerPage) ? Visibility.Hidden : Visibility.Visible;
        }

        private void ScrollTimerTick(object sender, EventArgs e)
        {
            if (_isMoveLeft)
            {
                _offset -= ControlWidth * Animation.AnimationStep;
                if (_offset <= -ControlWidth)
                {
                    CurrentItem--;
                    _offset = 0;
                    _animationTimer.Stop();
                }
            }
            else
            {
                _offset += ControlWidth * Animation.AnimationStep;
                if (_offset >= ControlWidth)
                {
                    CurrentItem++;
                    _offset = 0;
                    _animationTimer.Stop();
                }
            }

            ScrollPanel.ScrollToHorizontalOffset(CurrentItem * ControlWidth + _offset);

            if (IsAutoScroll)
            {
                _autoscrollTimer.Stop();
                _autoscrollTimer.Start();
            }
        }

        private void LeftButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ScrollToPrevItem();
            e.Handled = true;
        }

        private void RightButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ScrollToNextItem();
            e.Handled = true;
        }

        private void ScrollToPrevItem()
        {
            if (_animationTimer.IsEnabled) return;
            if (ContentPanel.Children.Count <= 1) return;

            if (CurrentItem == 0)
            {
                if (!IsCircularScroll) return;

                UIElement item = ContentPanel.Children[ContentPanel.Children.Count - 1];
                ContentPanel.Children.Remove(item);
                ContentPanel.Children.Insert(0, item);
                ScrollPanel.ScrollToHorizontalOffset(ControlWidth);
                CurrentItem++;
            }

            _isMoveLeft = true;
            _offset = 0;
            _animationTimer.Start();
        }

        private void ScrollToNextItem()
        {
            if (_animationTimer.IsEnabled) return;
            if (ContentPanel.Children.Count <= 1) return;

            if (CurrentItem >= ContentPanel.Children.Count - ControlsPerPage)
            {
                if (!IsCircularScroll) return;

                UIElement item = ContentPanel.Children[0];
                ContentPanel.Children.Remove(item);
                ContentPanel.Children.Add(item);
                CurrentItem--;
                ScrollPanel.ScrollToHorizontalOffset(CurrentItem * ControlWidth);
            }

            _isMoveLeft = false;
            _offset = 0;
            _animationTimer.Start();
        }

        public void Add(FrameworkElement element)
        {
            element.Width = ControlWidth;
            ContentPanel.Children.Add(element);
            UpdateNavigationButtons();

            if ((ScrollPanel.OpacityMask == null) && (ContentPanel.Children.Count >= ControlsPerPage))
            {
                ScrollPanel.OpacityMask = _opacityGradientBrush;
            }
        }

        public void Clear()
        {
            ContentPanel.Children.Clear();
        }

        public void ScrollToLeftEnd()
        {
            ScrollPanel.ScrollToLeftEnd();
            CurrentItem = 0;
        }
    }
}
